home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / access / transam / xact.c < prev   
Encoding:
C/C++ Source or Header  |  1992-08-27  |  36.4 KB  |  1,420 lines

  1. /* ----------------------------------------------------------------
  2.  *   FILE
  3.  *    xact.c
  4.  *    
  5.  *   DESCRIPTION
  6.  *    top level transaction system support routines
  7.  *
  8.  *   INTERFACE ROUTINES
  9.  *    StartTransactionCommand
  10.  *    CommitTransactionCommand
  11.  *    AbortCurrentTransaction
  12.  *    
  13.  *    StartTransactionBlock
  14.  *    CommitTransactionBlock
  15.  *    AbortTransactionBlock
  16.  *    
  17.  *    SlaveStartTransaction
  18.  *    SlaveCommitTransaction
  19.  *    SlaveAbortTransaction
  20.  *    
  21.  *   NEW CODE
  22.  *    * UserAbortTransactionBlock
  23.  *
  24.  *    Transaction aborts can now occur two ways:
  25.  *
  26.  *    1)  system dies from some internal cause  (Assert, etc..)
  27.  *    2)  user types abort
  28.  *
  29.  *    These two cases used to be treated identically, but now
  30.  *    we need to distinguish them.  Why?  consider the following
  31.  *    two situatuons:
  32.  *
  33.  *        case 1                case 2
  34.  *        ------                ------
  35.  *    1) user types BEGIN        1) user types BEGIN
  36.  *    2) user does something        2) user does something
  37.  *    3) user does not like what    3) system aborts for some reason
  38.  *       she shes and types ABORT       
  39.  *
  40.  *    In case 1, we want to abort the transaction and return to the
  41.  *    default state.  In case 2, there may be more commands coming
  42.  *    our way which are part of the same transaction block and we have
  43.  *    to ignore these commands until we see an END transaction.
  44.  *
  45.  *    Internal aborts are now handled by AbortTransactionBlock(), just as
  46.  *    they always have been, and user aborts are now handled by
  47.  *    UserAbortTransactionBlock().  Both of them rely on AbortTransaction()
  48.  *    to do all the real work.  The only difference is what state we
  49.  *    enter after AbortTransaction() does it's work:
  50.  *    
  51.  *    * AbortTransactionBlock() leaves us in TBLOCK_ABORT and
  52.  *    * UserAbortTransactionBlock() leaves us in TBLOCK_ENDABORT
  53.  *    
  54.  *   NOTES
  55.  *    This file is an attempt at a redesign of the upper layer
  56.  *    of the V1 transaction system which was too poorly thought
  57.  *    out to describe.  This new system hopes to be both simpler
  58.  *    in design, simpler to extend and needs to contain added
  59.  *    functionality to solve problems beyond the scope of the V1
  60.  *    system.  (In particuler, communication of transaction
  61.  *    information between parallel backends has to be supported)
  62.  *
  63.  *    The essential aspects of the transaction system are:
  64.  *
  65.  *        o  transaction id generation
  66.  *        o  transaction log updating
  67.  *        o  memory cleanup
  68.  *        o  cache invalidation
  69.  *        o  lock cleanup
  70.  *
  71.  *    Hence, the functional division of the transaction code is
  72.  *    based on what of the above things need to be done during
  73.  *    a start/commit/abort transaction.  For instance, the
  74.  *    routine AtCommit_Memory() takes care of all the memory
  75.  *    cleanup stuff done at commit time.
  76.  *
  77.  *    The code is layered as follows:
  78.  *
  79.  *        StartTransaction
  80.  *        CommitTransaction
  81.  *        AbortTransaction
  82.  *        UserAbortTransaction
  83.  *
  84.  *    are provided to do the lower level work like recording
  85.  *    the transaction status in the log and doing memory cleanup.
  86.  *    above these routines are another set of functions:
  87.  *
  88.  *        StartTransactionCommand
  89.  *        CommitTransactionCommand
  90.  *        AbortCurrentTransaction
  91.  *
  92.  *    These are the routines used in the postgres main processing
  93.  *    loop.  They are sensitive to the current transaction block state
  94.  *    and make calls to the lower level routines appropriately.
  95.  *
  96.  *    Support for transaction blocks is provided via the functions:
  97.  *
  98.  *        StartTransactionBlock
  99.  *        CommitTransactionBlock
  100.  *        AbortTransactionBlock
  101.  *
  102.  *    These are invoked only in responce to a user "BEGIN", "END",
  103.  *    or "ABORT" command.  The tricky part about these functions
  104.  *    is that they are called within the postgres main loop, in between
  105.  *    the StartTransactionCommand() and CommitTransactionCommand().
  106.  *
  107.  *    For example, consider the following sequence of user commands:
  108.  *
  109.  *    1)    begin
  110.  *    2)    retrieve (foo.all)
  111.  *    3)    append foo (bar = baz)
  112.  *    4)    end
  113.  *
  114.  *    in the main processing loop, this results in the following
  115.  *    transaction sequence:
  116.  *
  117.  *        /    StartTransactionCommand();
  118.  *    1) /    ProcessUtility();         << begin
  119.  *       \        StartTransactionBlock();
  120.  *        \    CommitTransactionCommand();
  121.  *
  122.  *        /    StartTransactionCommand();
  123.  *    2) <    ProcessQuery();            << retrieve (foo.all)
  124.  *        \    CommitTransactionCommand();
  125.  *
  126.  *        /    StartTransactionCommand();
  127.  *    3) <    ProcessQuery();            << append foo (bar = baz)
  128.  *        \    CommitTransactionCommand();
  129.  *
  130.  *        /    StartTransactionCommand();
  131.  *    4) /    ProcessUtility();         << end
  132.  *       \        CommitTransactionBlock();
  133.  *        \    CommitTransactionCommand();
  134.  *
  135.  *    The point of this example is to demonstrate the need for
  136.  *    StartTransactionCommand() and CommitTransactionCommand() to
  137.  *    be state smart -- they should do nothing in between the calls
  138.  *    to StartTransactionBlock() and EndTransactionBlock() and
  139.  *      outside these calls they need to do normal start/commit
  140.  *    processing.
  141.  *
  142.  *    Furthermore, suppose the "retrieve (foo.all)" caused an abort
  143.  *    condition.  We would then want to abort the transaction and
  144.  *    ignore all subsequent commands up to the "end".
  145.  *    -cim 3/23/90
  146.  *
  147.  *    The "slave" transction routines are used within the parallel
  148.  *    slave ackends.
  149.  *
  150.  *        SlaveStartTransaction
  151.  *        SlaveCommitTransaction
  152.  *        SlaveAbortTransaction
  153.  *    
  154.  *    Since slave backends do none of the log or transaction state
  155.  *    processing, these routines only preform cache, lock table
  156.  *    and memory initialization/cleanup duties needed by the rest
  157.  *    of the system.
  158.  *
  159.  *   IDENTIFICATION
  160.  *    $Header: /private/postgres/src/access/transam/RCS/xact.c,v 1.29 1992/08/18 18:27:16 mer Exp $
  161.  * ----------------------------------------------------------------
  162.  */
  163.  
  164. #include "tmp/postgres.h"
  165. #include "access/xact.h"
  166.  
  167.  RcsId("$Header: /private/postgres/src/access/transam/RCS/xact.c,v 1.29 1992/08/18 18:27:16 mer Exp $");
  168.  
  169. /* ----------------
  170.  *    global variables holding the current transaction state.
  171.  *
  172.  *      Note: when we are running several slave processes, the
  173.  *            current transaction state data is copied into shared memory
  174.  *          and the CurrentTransactionState pointer changed to
  175.  *          point to the shared copy.  All this occurrs in slaves.c
  176.  * ----------------
  177.  */
  178. TransactionStateData CurrentTransactionStateData = {
  179.     0,                /* transaction id */
  180.     FirstCommandId,        /* command id */
  181.     0x0,            /* start time */
  182.     TRANS_DEFAULT,        /* transaction state */
  183.     TBLOCK_DEFAULT        /* transaction block state */
  184. };
  185.  
  186. TransactionState CurrentTransactionState =
  187.     &CurrentTransactionStateData;
  188.  
  189. /* ----------------
  190.  *    slave-local transaction state.  This is only used by
  191.  *    the parallel slave backend transaction code.
  192.  * ----------------
  193.  */
  194. bool inSlaveTransaction = false;
  195.  
  196. /* ----------------
  197.  *    info returned when the system is desabled
  198.  *
  199.  *    Note:  I have no idea what the significance of the
  200.  *           1073741823 in DisabledStartTime.. I just carried
  201.  *           this over when converting things from the old
  202.  *           V1 transaction system.  -cim 3/18/90
  203.  * ----------------
  204.  */
  205. TransactionId DisabledTransactionId = (TransactionId)-1;
  206.  
  207. CommandId DisabledCommandId =
  208.     (CommandId) -1;
  209.  
  210. Time DisabledStartTime =
  211.     (Time) 1073741823;
  212.  
  213. /* ----------------
  214.  *    overflow flag
  215.  * ----------------
  216.  */
  217. bool CommandIdCounterOverflowFlag;
  218.  
  219. /* ----------------
  220.  *    catalog creation transaction bootstrapping flag.
  221.  *    This should be eliminated and added to the transaction
  222.  *    state stuff.  -cim 3/19/90
  223.  * ----------------
  224.  */
  225. bool AMI_OVERRIDE = false;
  226.  
  227. /* ----------------------------------------------------------------
  228.  *             transaction state accessors
  229.  * ----------------------------------------------------------------
  230.  */
  231.  
  232. /* --------------------------------
  233.  *    TranactionFlushEnabled()
  234.  *    SetTranactionFlushEnabled()
  235.  *
  236.  *    These are used to test and set the "TransactionFlushState"
  237.  *    varable.  If this variable is true (the default), then
  238.  *    the system will flush all dirty buffers to disk at the end
  239.  *    of each transaction.   If false then we are assuming the
  240.  *    buffer pool resides in stable main memory, in which case we
  241.  *    only do writes as necessary.
  242.  * --------------------------------
  243.  */
  244. int TransactionFlushState = 1;
  245.  
  246. int
  247. TransactionFlushEnabled()
  248. {    
  249.     return TransactionFlushState;
  250. }
  251.  
  252. void
  253. SetTransactionFlushEnabled(state)
  254.     bool state;
  255. {    
  256.     TransactionFlushState = (state == true);
  257. }
  258.  
  259. /* --------------------------------
  260.  *    IsTransactionState
  261.  *
  262.  *    This returns true if we are currently running a query
  263.  *    within an executing transaction.
  264.  * --------------------------------
  265.  */
  266. bool
  267. IsTransactionState()
  268. {
  269.     TransactionState s = CurrentTransactionState;
  270.  
  271.     switch (s->state) {
  272.     case TRANS_DEFAULT:        return false;
  273.     case TRANS_START:        return true;
  274.     case TRANS_INPROGRESS:    return true;
  275.     case TRANS_COMMIT:        return true;
  276.     case TRANS_ABORT:        return true;
  277.     case TRANS_DISABLED:    return false;
  278.     }
  279.     /*
  280.      * Shouldn't get here, but lint is not happy with this...
  281.      */
  282.     return(false);
  283. }
  284.  
  285. /* --------------------------------
  286.  *    IsAbortedTransactionBlockState
  287.  *
  288.  *    This returns true if we are currently running a query
  289.  *    within an aborted transaction block.
  290.  * --------------------------------
  291.  */
  292. bool
  293. IsAbortedTransactionBlockState()
  294. {
  295.     TransactionState s = CurrentTransactionState;
  296.  
  297.     if (s->blockState == TBLOCK_ABORT)
  298.     return true;
  299.  
  300.     return false;
  301. }
  302.  
  303. /* --------------------------------
  304.  *    OverrideTransactionSystem
  305.  *
  306.  *    This is used to temporarily disable the transaction
  307.  *    processing system in order to do initialization of
  308.  *    the transaction system data structures and relations
  309.  *    themselves.
  310.  * --------------------------------
  311.  */
  312. int SavedTransactionState;
  313.  
  314. void
  315. OverrideTransactionSystem(flag)
  316.     bool flag;
  317. {
  318.     TransactionState s = CurrentTransactionState;
  319.  
  320.     if (flag == true) {
  321.     if (s->state == TRANS_DISABLED)
  322.         return;
  323.  
  324.     SavedTransactionState = s->state;
  325.     s->state = TRANS_DISABLED;
  326.     } else {
  327.     if (s->state != TRANS_DISABLED)
  328.         return;
  329.  
  330.     s->state = SavedTransactionState;
  331.     }
  332. }
  333.  
  334. /* --------------------------------
  335.  *    GetCurrentTransactionId
  336.  *
  337.  *    This returns the id of the current transaction, or
  338.  *    the id of the "disabled" transaction.
  339.  * --------------------------------
  340.  */
  341. TransactionId
  342. GetCurrentTransactionId()
  343. {
  344.     TransactionState s = CurrentTransactionState;
  345.  
  346.     /* ----------------
  347.      *    if the transaction system is disabled, we return
  348.      *  the special "disabled" transaction id.
  349.      * ----------------
  350.      */
  351.     if (s->state == TRANS_DISABLED)
  352.     return (TransactionId) DisabledTransactionId;
  353.  
  354.     /* ----------------
  355.      *    otherwise return the current transaction id.
  356.      * ----------------
  357.      */
  358.     return (TransactionId) s->transactionIdData;
  359. }
  360.  
  361.  
  362. /* --------------------------------
  363.  *    GetCurrentCommandId
  364.  * --------------------------------
  365.  */
  366. CommandId
  367. GetCurrentCommandId()
  368. {
  369.     TransactionState s = CurrentTransactionState;
  370.  
  371.     /* ----------------
  372.      *    if the transaction system is disabled, we return
  373.      *  the special "disabled" command id.
  374.      * ----------------
  375.      */
  376.     if (s->state == TRANS_DISABLED)
  377.     return (CommandId) DisabledCommandId;
  378.  
  379.     return s->commandId;
  380. }
  381.  
  382.  
  383. /* --------------------------------
  384.  *    GetCurrentTransactionStartTime
  385.  * --------------------------------
  386.  */
  387. Time
  388. GetCurrentTransactionStartTime()
  389. {
  390.     TransactionState s = CurrentTransactionState;
  391.  
  392.     /* ----------------
  393.      *    if the transaction system is disabled, we return
  394.      *  the special "disabled" starting time.
  395.      * ----------------
  396.      */
  397.     if (s->state == TRANS_DISABLED)
  398.     return (Time) DisabledStartTime;
  399.     
  400.     return s->startTime;
  401. }
  402.     
  403.  
  404. /* --------------------------------
  405.  *    TransactionIdIsCurrentTransactionId
  406.  * --------------------------------
  407.  */
  408. bool
  409. TransactionIdIsCurrentTransactionId(xid)
  410.     TransactionId    xid;
  411. {
  412.     TransactionState s = CurrentTransactionState;
  413.     
  414.     if (AMI_OVERRIDE)
  415.     return false;
  416.  
  417.     return (bool)
  418.     TransactionIdEquals(xid, s->transactionIdData);
  419. }
  420.  
  421.  
  422. /* --------------------------------
  423.  *    CommandIdIsCurrentCommandId
  424.  * --------------------------------
  425.  */
  426. bool
  427. CommandIdIsCurrentCommandId(cid)
  428.     CommandId cid;
  429. {
  430.     TransactionState s = CurrentTransactionState;
  431.     
  432.     if (AMI_OVERRIDE)
  433.     return false;
  434.  
  435.     return     
  436.     (cid == s->commandId) ? true : false;
  437. }
  438.  
  439.  
  440. /* --------------------------------
  441.  *    ClearCommandIdCounterOverflowFlag
  442.  * --------------------------------
  443.  */
  444. void
  445. ClearCommandIdCounterOverflowFlag()
  446. {
  447.     CommandIdCounterOverflowFlag = false;
  448. }
  449.  
  450.  
  451. /* --------------------------------
  452.  *    CommandCounterIncrement
  453.  * --------------------------------
  454.  */
  455. void    
  456. CommandCounterIncrement()
  457. {
  458.     CurrentTransactionStateData.commandId += 1;
  459.     if (CurrentTransactionStateData.commandId == FirstCommandId) {
  460.     CommandIdCounterOverflowFlag = true;
  461.     elog(WARN, "You may only have 65535 commands per transaction");
  462.     }
  463.  
  464.     /* make cache changes visible to me */
  465.     AtCommit_Cache();
  466.     AtStart_Cache();
  467. }
  468.  
  469. /* ----------------------------------------------------------------
  470.  *                initialization stuff
  471.  * ----------------------------------------------------------------
  472.  */
  473.  
  474. void
  475. InitializeTransactionSystem()
  476. {
  477.     InitializeTransactionLog();
  478. }
  479.  
  480. /* ----------------------------------------------------------------
  481.  *                StartTransaction stuff
  482.  * ----------------------------------------------------------------
  483.  */
  484.  
  485. /* --------------------------------
  486.  *    AtStart_Cache
  487.  * --------------------------------
  488.  */
  489. void
  490. AtStart_Cache()    
  491. {
  492.     DiscardInvalid();
  493. }
  494.  
  495. /* --------------------------------
  496.  *    AtStart_Locks
  497.  * --------------------------------
  498.  */
  499. void
  500. AtStart_Locks()    
  501. {
  502.     /*
  503.      * at present, it is unknown to me what belongs here -cim 3/18/90
  504.      *
  505.      * There isn't anything to do at the start of a xact for locks.
  506.      *  -mer 5/24/92
  507.      */
  508. }
  509.  
  510. /* --------------------------------
  511.  *    AtStart_Memory
  512.  * --------------------------------
  513.  */
  514. void
  515. AtStart_Memory()    
  516. {
  517.     Portal         portal;
  518.     MemoryContext    portalContext;
  519.  
  520.     /* ----------------
  521.      *    get the blank portal and its memory context
  522.      * ----------------
  523.      */
  524.     portal = GetPortalByName(NULL);
  525.     portalContext = (MemoryContext) PortalGetHeapMemory(portal);
  526.  
  527.     /* ----------------
  528.      *    tell system to allocate in the blank portal context
  529.      * ----------------
  530.      */
  531.     (void) MemoryContextSwitchTo(portalContext);
  532.     StartPortalAllocMode(DefaultAllocMode, 0);
  533. }
  534.  
  535.  
  536. /* ----------------------------------------------------------------
  537.  *                CommitTransaction stuff
  538.  * ----------------------------------------------------------------
  539.  */
  540.  
  541. /* --------------------------------
  542.  *    RecordTransactionCommit
  543.  *
  544.  *    Note: the two calls to BufferManagerFlush() exist to ensure
  545.  *          that data pages are written before log pages.  These
  546.  *          explicit calls should be replaced by a more efficient
  547.  *          ordered page write scheme in the buffer manager
  548.  *          -cim 3/18/90
  549.  * --------------------------------
  550.  */
  551. void
  552. RecordTransactionCommit()    
  553. {
  554.     TransactionId xid;
  555.     int leak;
  556.  
  557.     /* ----------------
  558.      *    get the current transaction id
  559.      * ----------------
  560.      */
  561.     xid = GetCurrentTransactionId();
  562.     
  563.     /* ----------------
  564.      *    flush the buffer manager pages.  Note: if we have stable
  565.      *  main memory, dirty shared buffers are not flushed
  566.      *  plai 8/7/90
  567.      * ----------------
  568.      */
  569.     leak = BufferPoolCheckLeak();
  570.     FlushBufferPool(!TransactionFlushEnabled());
  571.     if (leak) ResetBufferPool();
  572.     
  573.     /* ----------------
  574.      *    have the transaction access methods record the status
  575.      *  of this transaction id in the pg_log / pg_time relations.
  576.      * ----------------
  577.      */
  578.     TransactionIdCommit(xid);
  579.     
  580.     /* ----------------
  581.      *    Now write the log/time info to the disk too.
  582.      * ----------------
  583.      */
  584.     leak = BufferPoolCheckLeak();
  585.     FlushBufferPool(!TransactionFlushEnabled());
  586.     if (leak) ResetBufferPool();
  587. }
  588.  
  589.  
  590. /* --------------------------------
  591.  *    AtCommit_Cache
  592.  * --------------------------------
  593.  */
  594. void
  595. AtCommit_Cache()
  596. {
  597.     /* ----------------
  598.      * Make catalog changes visible to me for the next command.
  599.      * Other backends will not process my invalidation messages until
  600.      * after I commit and free my locks--though they will do
  601.      * unnecessary work if I abort.
  602.      * ----------------
  603.      */
  604.     RegisterInvalid(true);
  605. }
  606.  
  607. /* --------------------------------
  608.  *    AtCommit_Locks
  609.  * --------------------------------
  610.  */
  611. void
  612. AtCommit_Locks()  
  613. {
  614.     /* ----------------
  615.      *    XXX What if ProcReleaseLocks fails?  (race condition?) 
  616.      *
  617.      *  Then you're up a creek! -mer 5/24/92
  618.      * ----------------
  619.      */
  620.     ProcReleaseLocks();
  621. }
  622.  
  623. /* --------------------------------
  624.  *    AtCommit_Memory
  625.  * --------------------------------
  626.  */
  627. void
  628. AtCommit_Memory()  
  629. {
  630.     /* ----------------
  631.      *    now that we're "out" of a transaction, have the
  632.      *  system allocate things in the top memory context instead
  633.      *  of the blank portal memory context.
  634.      * ----------------
  635.      */
  636.     EndPortalAllocMode();
  637.     (void) MemoryContextSwitchTo(TopMemoryContext);
  638. }
  639.  
  640. /* ----------------------------------------------------------------
  641.  *                AbortTransaction stuff
  642.  * ----------------------------------------------------------------
  643.  */
  644.  
  645. /* --------------------------------
  646.  *    RecordTransactionAbort
  647.  * --------------------------------
  648.  */
  649. void
  650. RecordTransactionAbort()    
  651. {
  652.     TransactionId xid;
  653.  
  654.     /* ----------------
  655.      *    get the current transaction id
  656.      * ----------------
  657.      */
  658.     xid = GetCurrentTransactionId();
  659.     
  660.     /* ----------------
  661.      *    have the transaction access methods record the status
  662.      *  of this transaction id in the pg_log / pg_time relations.
  663.      * ----------------
  664.      */
  665.     TransactionIdAbort(xid);
  666.     
  667.     /* ----------------
  668.      *    flush the buffer manager pages.  Note: if we have stable
  669.      *  main memory, dirty shared buffers are not flushed
  670.      *  plai 8/7/90
  671.      * ----------------
  672.      */
  673.     ResetBufferPool(!TransactionFlushEnabled());
  674. }
  675.  
  676. /* --------------------------------
  677.  *    AtAbort_Cache
  678.  * --------------------------------
  679.  */
  680. void
  681. AtAbort_Cache()    
  682. {
  683.     RegisterInvalid(false);
  684. }
  685.  
  686. /* --------------------------------
  687.  *    AtAbort_Locks
  688.  * --------------------------------
  689.  */
  690. void
  691. AtAbort_Locks()    
  692. {
  693.     /* ----------------
  694.      *    XXX What if ProcReleaseLocks() fails?  (race condition?)
  695.      *
  696.      *  Then you're up a creek without a paddle! -mer
  697.      * ----------------
  698.      */
  699.     ProcReleaseLocks();
  700. }
  701.  
  702.  
  703. /* --------------------------------
  704.  *    AtAbort_Memory
  705.  * --------------------------------
  706.  */
  707. void
  708. AtAbort_Memory()    
  709. {
  710.     /* ----------------
  711.      *    after doing an abort transaction, make certain the
  712.      *  system uses the top memory context rather then the
  713.      *  portal memory context (until the next transaction).
  714.      * ----------------
  715.      */
  716.     (void) MemoryContextSwitchTo(TopMemoryContext);
  717. }
  718.  
  719. /* ----------------------------------------------------------------
  720.  *            interface routines
  721.  * ----------------------------------------------------------------
  722.  */
  723.  
  724. /* --------------------------------
  725.  *    StartTransaction
  726.  *
  727.  * --------------------------------
  728.  */
  729. void
  730. StartTransaction()
  731. {
  732.     TransactionState s = CurrentTransactionState;
  733.     extern bool    TransactionInitWasProcessed;    /* XXX style */
  734.  
  735.     /* ----------------
  736.      *    Check the current transaction state.  If the transaction system
  737.      *  is switched off, or if we're already in a transaction, do nothing.
  738.      *  We're already in a transaction when the monitor sends a null
  739.      *  command to the backend to flush the comm channel.  This is a
  740.      *  hacky fix to a communications problem, and we keep having to
  741.      *  deal with it here.  We should fix the comm channel code.  mao 080891
  742.      * ----------------
  743.      */
  744.     if (s->state == TRANS_DISABLED || s->state == TRANS_INPROGRESS)
  745.     return;
  746.  
  747.     /* ----------------
  748.      *    set the current transaction state information
  749.      *  appropriately during start processing
  750.      * ----------------
  751.      */
  752.     s->state = TRANS_START;
  753.     
  754.     /* ----------------
  755.      *    generate a new transaction id
  756.      * ----------------
  757.      */
  758.     GetNewTransactionId(&(s->transactionIdData));
  759.     
  760.     /* ----------------
  761.      *    initialize current transaction state fields
  762.      * ----------------
  763.      */
  764.     s->commandId =         FirstCommandId;
  765.     s->startTime =         GetCurrentTime();
  766.  
  767.     /* ----------------
  768.      *    initialize the various transaction subsystems
  769.      * ----------------
  770.      */
  771.     AtStart_Cache();
  772.     AtStart_Locks();
  773.     AtStart_Memory();
  774.  
  775.     /* ----------------
  776.      *    done with start processing, set current transaction
  777.      *  state to "in progress"
  778.      * ----------------
  779.      */
  780.     s->state = TRANS_INPROGRESS;      
  781. }
  782.  
  783. /* ---------------
  784.  * Tell me if we are currently in progress
  785.  * ---------------
  786.  */
  787. bool
  788. CurrentXactInProgress()
  789. {
  790.     return (CurrentTransactionState->state == TRANS_INPROGRESS);
  791. }
  792.  
  793. /* --------------------------------
  794.  *    CommitTransaction
  795.  *
  796.  * --------------------------------
  797.  */
  798. void
  799. CommitTransaction()
  800. {
  801.     TransactionState s = CurrentTransactionState;
  802.  
  803.     /* ----------------
  804.      *    check the current transaction state
  805.      * ----------------
  806.      */
  807.     if (s->state == TRANS_DISABLED)
  808.     return;
  809.     
  810.     if (s->state != TRANS_INPROGRESS)
  811.     elog(NOTICE, "CommitTransaction and not in in-progress state ");
  812.     
  813.     /* ----------------
  814.      *    set the current transaction state information
  815.      *  appropriately during the abort processing
  816.      * ----------------
  817.      */
  818.     s->state = TRANS_COMMIT;
  819.  
  820.     /* ----------------
  821.      *    do commit processing
  822.      * ----------------
  823.      */
  824.     AtEOXact_portals();
  825.     RecordTransactionCommit();
  826.     AtCommit_LocalRels();
  827.     AtCommit_Cache();
  828.     AtCommit_Locks();
  829.     AtCommit_Memory();
  830.  
  831.     /* ----------------
  832.      *    done with commit processing, set current transaction
  833.      *  state back to default
  834.      * ----------------
  835.      */
  836.     s->state = TRANS_DEFAULT;    
  837.     {                /* want this after commit */
  838.     extern void Async_NotifyAtCommit();
  839.     if (IsNormalProcessingMode())
  840.       Async_NotifyAtCommit();
  841.     }
  842. }
  843.  
  844. /* --------------------------------
  845.  *    AbortTransaction
  846.  *
  847.  * --------------------------------
  848.  */
  849. void
  850. AbortTransaction()
  851. {
  852.     TransactionState s = CurrentTransactionState;
  853.  
  854.     /* ----------------
  855.      *    check the current transaction state
  856.      * ----------------
  857.      */
  858.     if (s->state == TRANS_DISABLED)
  859.     return;
  860.     
  861.     if (s->state != TRANS_INPROGRESS)
  862.     elog(NOTICE, "AbortTransaction and not in in-progress state ");
  863.     
  864.     /* ----------------
  865.      *    set the current transaction state information
  866.      *  appropriately during the abort processing
  867.      * ----------------
  868.      */
  869.     s->state = TRANS_ABORT;
  870.         
  871.     /* ----------------
  872.      *    do abort processing
  873.      * ----------------
  874.      */
  875.     AtEOXact_portals();
  876.     RecordTransactionAbort();
  877.     AtAbort_LocalRels();
  878.     AtAbort_Cache();
  879.     AtAbort_Locks();
  880.     AtAbort_Memory();
  881.  
  882.     /* ----------------
  883.      *    done with abort processing, set current transaction
  884.      *  state back to default
  885.      * ----------------
  886.      */
  887.     s->state = TRANS_DEFAULT;
  888. }
  889.  
  890. /* ----------------------------------------------------------------
  891.  *        slave backend transaction interface
  892.  *
  893.  *    These functions take care of doing the proper transaction
  894.  *      processing when we are running inside a slave backend.
  895.  *
  896.  *      Since the master backend calls StartTransactionCommand(),
  897.  *    CommitTransactionCommand() and AbortCurrentTransaction(),
  898.  *    it ends up doing all the real work.
  899.  *
  900.  *    The slaves only have to do cache, lock table and memory
  901.  *    cleanup to support the parts of the system which don't
  902.  *    understand parallel processing.  Slaves don't touch the
  903.  *    log or the transaction state because the master backend
  904.  *    does this.  The slave-local transaction state is updated.
  905.  * ----------------------------------------------------------------
  906.  */
  907.  
  908. /* --------------------------------
  909.  *    SlaveStartTransaction
  910.  *
  911.  * --------------------------------
  912.  */
  913. void
  914. SlaveStartTransaction()
  915. {
  916.     AtStart_Cache();
  917.     AtStart_Locks();
  918.     AtStart_Memory();
  919.     
  920.     inSlaveTransaction = true;
  921. }
  922.  
  923. /* --------------------------------
  924.  *    SlaveCommitTransaction
  925.  *
  926.  * --------------------------------
  927.  */
  928. void
  929. SlaveCommitTransaction()
  930. {
  931.     AtCommit_LocalRels();
  932.     AtCommit_Cache();
  933.     AtCommit_Locks();
  934.     AtCommit_Memory();
  935.     
  936.     inSlaveTransaction = false;
  937. }
  938.  
  939. /* --------------------------------
  940.  *    SlaveAbortTransaction
  941.  *
  942.  *    Note: Since AtAbort_Memory does no memory cleanup, we
  943.  *          call AtCommit_Memory instead.
  944.  * --------------------------------
  945.  */
  946. void
  947. SlaveAbortTransaction()
  948. {
  949.     AtAbort_LocalRels();
  950.     AtAbort_Cache();
  951.     AtAbort_Locks();
  952.     AtCommit_Memory();
  953.     
  954.     inSlaveTransaction = false;
  955. }
  956.  
  957. /* --------------------------------
  958.  *    InSlaveTransaction
  959.  *
  960.  *    returns 1 if we are "in" a slave transaction.  This
  961.  *    is used by the slave abort code to determine if we don't
  962.  *    need to do abort cleanup in the slaves.
  963.  * --------------------------------
  964.  */
  965. int
  966. InSlaveTransaction()
  967. {
  968.     return (inSlaveTransaction == true);
  969. }
  970.  
  971. /* ----------------------------------------------------------------
  972.  *    transaction system interface functions.   these provide
  973.  *    support for transaction blocks above the start / abort /
  974.  *    commit transaction routines above.
  975.  * ----------------------------------------------------------------
  976.  */
  977.  
  978. /* --------------------------------
  979.  *    StartTransactionCommand
  980.  * --------------------------------
  981.  */
  982. void
  983. StartTransactionCommand()
  984. {
  985.     TransactionState s = CurrentTransactionState;
  986.  
  987.     switch(s->blockState) {
  988.     /* ----------------
  989.      *    if we aren't in a transaction block, we
  990.      *    just do our usual start transaction.
  991.      * ----------------
  992.      */
  993.     case TBLOCK_DEFAULT:
  994.     StartTransaction();
  995.     break;
  996.     
  997.     /* ----------------
  998.      *    We should never experience this -- if we do it
  999.      *    means the BEGIN state was not changed in the previous
  1000.      *    CommitTransactionCommand().  If we get it, we print
  1001.      *    a warning and change to the in-progress state.
  1002.      * ----------------
  1003.      */
  1004.     case TBLOCK_BEGIN:
  1005.     elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_BEGIN");
  1006.     s->blockState = TBLOCK_INPROGRESS;
  1007.     break;
  1008.     
  1009.     /* ----------------
  1010.      *    This is the case when are somewhere in a transaction
  1011.      *    block and about to start a new command.  For now we
  1012.      *    do nothing but someday we may do command-local resource
  1013.      *    initialization.
  1014.      * ----------------
  1015.      */
  1016.     case TBLOCK_INPROGRESS:
  1017.     break;
  1018.  
  1019.     /* ----------------
  1020.      *    As with BEGIN, we should never experience this --
  1021.      *    if we do it means the END state was not changed in the
  1022.      *    previous CommitTransactionCommand().  If we get it, we
  1023.      *    print a warning, commit the transaction, start a new
  1024.      *    transaction and change to the default state.
  1025.      * ----------------
  1026.      */
  1027.     case TBLOCK_END:
  1028.     elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_END");
  1029.     s->blockState = TBLOCK_DEFAULT;
  1030.     CommitTransaction();
  1031.     StartTransaction();
  1032.     break;
  1033.  
  1034.     /* ----------------
  1035.      *    Here we are in the middle of a transaction block but
  1036.      *    one of the commands caused an abort so we do nothing
  1037.      *    but remain in the abort state.  Eventually we will get
  1038.      *    to the "END TRANSACTION" which will set things straight.
  1039.      * ----------------
  1040.      */
  1041.     case TBLOCK_ABORT:
  1042.     break;    
  1043.  
  1044.     /* ----------------
  1045.      *    This means we somehow aborted and the last call to
  1046.      *    CommitTransactionCommand() didn't clear the state so
  1047.      *    we remain in the ENDABORT state and mabey next time
  1048.      *    we get to CommitTransactionCommand() the state will
  1049.      *    get reset to default.
  1050.      * ----------------
  1051.      */
  1052.     case TBLOCK_ENDABORT:
  1053.     elog(NOTICE, "StartTransactionCommand: unexpected TBLOCK_ENDABORT");
  1054.     break;    
  1055.     }    
  1056. }
  1057. /* --------------------------------
  1058.  *    CommitTransactionCommand
  1059.  * --------------------------------
  1060.  */
  1061. void
  1062. CommitTransactionCommand()
  1063. {
  1064.     TransactionState s = CurrentTransactionState;
  1065.  
  1066.     switch(s->blockState) {
  1067.     /* ----------------
  1068.      *    if we aren't in a transaction block, we
  1069.      *    just do our usual transaction commit
  1070.      * ----------------
  1071.      */
  1072.     case TBLOCK_DEFAULT:
  1073.     CommitTransaction();
  1074.     break;
  1075.  
  1076.     /* ----------------
  1077.      *    This is the case right after we get a "BEGIN TRANSACTION"
  1078.      *    command, but the user hasn't done anything else yet, so
  1079.      *    we change to the "transaction block in progress" state
  1080.      *    and return.   
  1081.      * ----------------
  1082.      */
  1083.     case TBLOCK_BEGIN:
  1084.     s->blockState = TBLOCK_INPROGRESS;
  1085.     break;
  1086.  
  1087.     /* ----------------
  1088.      *    This is the case when we have finished executing a command
  1089.      *    someplace within a transaction block.  We increment the
  1090.      *    command counter and return.  Someday we may free resources
  1091.      *    local to the command.
  1092.      * ----------------
  1093.      */
  1094.     case TBLOCK_INPROGRESS:
  1095.     CommandCounterIncrement();
  1096.     break;
  1097.  
  1098.     /* ----------------
  1099.      *    This is the case when we just got the "END TRANSACTION"
  1100.      *    statement, so we go back to the default state and
  1101.      *    commit the transaction.
  1102.      * ----------------
  1103.      */
  1104.     case TBLOCK_END:
  1105.     s->blockState = TBLOCK_DEFAULT;
  1106.     CommitTransaction();
  1107.     break;
  1108.     
  1109.     /* ----------------
  1110.      *    Here we are in the middle of a transaction block but
  1111.      *    one of the commands caused an abort so we do nothing
  1112.      *    but remain in the abort state.  Eventually we will get
  1113.      *    to the "END TRANSACTION" which will set things straight.
  1114.      * ----------------
  1115.      */
  1116.     case TBLOCK_ABORT:
  1117.     break;
  1118.     
  1119.     /* ----------------
  1120.      *    Here we were in an aborted transaction block which
  1121.      *      just processed the "END TRANSACTION" command from the
  1122.      *    user, so now we return the to default state.
  1123.      * ----------------
  1124.      */
  1125.     case TBLOCK_ENDABORT:
  1126.     s->blockState = TBLOCK_DEFAULT;  
  1127.     break;
  1128.     }    
  1129. }
  1130.  
  1131. /* --------------------------------
  1132.  *    AbortCurrentTransaction
  1133.  * --------------------------------
  1134.  */
  1135. void
  1136. AbortCurrentTransaction()
  1137. {
  1138.     TransactionState s = CurrentTransactionState;
  1139.     
  1140.     switch(s->blockState) {
  1141.     /* ----------------
  1142.      *    if we aren't in a transaction block, we
  1143.      *    just do our usual abort transaction.
  1144.      * ----------------
  1145.      */
  1146.     case TBLOCK_DEFAULT:
  1147.     AbortTransaction();
  1148.     break;
  1149.  
  1150.     /* ----------------
  1151.      *    If we are in the TBLOCK_BEGIN it means something
  1152.      *    screwed up right after reading "BEGIN TRANSACTION"
  1153.      *    so we enter the abort state.  Eventually an "END
  1154.      *      TRANSACTION" will fix things.
  1155.      * ----------------
  1156.      */
  1157.     case TBLOCK_BEGIN:
  1158.     s->blockState = TBLOCK_ABORT;
  1159.     AbortTransaction();
  1160.     break;
  1161.         
  1162.     /* ----------------
  1163.      *    This is the case when are somewhere in a transaction
  1164.      *    block which aborted so we abort the transaction and
  1165.      *    set the ABORT state.  Eventually an "END TRANSACTION"
  1166.      *    will fix things and restore us to a normal state.
  1167.      * ----------------
  1168.      */
  1169.     case TBLOCK_INPROGRESS:
  1170.     s->blockState = TBLOCK_ABORT;
  1171.     AbortTransaction();
  1172.     break;
  1173.  
  1174.     /* ----------------
  1175.      *    Here, the system was fouled up just after the
  1176.      *    user wanted to end the transaction block so we
  1177.      *    abort the transaction and put us back into the
  1178.      *    default state.
  1179.      * ----------------
  1180.      */
  1181.     case TBLOCK_END:
  1182.     s->blockState = TBLOCK_DEFAULT;
  1183.     AbortTransaction();
  1184.     break;
  1185.  
  1186.     /* ----------------
  1187.      *    Here, we are already in an aborted transaction
  1188.      *    state and are waiting for an "END TRANSACTION" to
  1189.      *    come along and lo and behold, we abort again!
  1190.      *    So we just remain in the abort state.
  1191.      * ----------------
  1192.      */
  1193.     case TBLOCK_ABORT:
  1194.     break;
  1195.     
  1196.     /* ----------------
  1197.      *    Here we were in an aborted transaction block which
  1198.      *      just processed the "END TRANSACTION" command but somehow
  1199.      *    aborted again.. since we must have done the abort
  1200.      *      processing, we return to the default state.
  1201.      * ----------------
  1202.      */
  1203.     case TBLOCK_ENDABORT:
  1204.     s->blockState = TBLOCK_DEFAULT;  
  1205.     break;
  1206.     }
  1207. }
  1208.  
  1209. /* ----------------------------------------------------------------
  1210.  *               transaction block support
  1211.  * ----------------------------------------------------------------
  1212.  */
  1213. /* --------------------------------
  1214.  *    BeginTransactionBlock
  1215.  * --------------------------------
  1216.  */
  1217. void
  1218. BeginTransactionBlock()
  1219. {
  1220.     TransactionState s = CurrentTransactionState;
  1221.  
  1222.     /* ----------------
  1223.      *    check the current transaction state
  1224.      * ----------------
  1225.      */
  1226.     if (s->state == TRANS_DISABLED)
  1227.     return;
  1228.     
  1229.     if (s->blockState != TBLOCK_DEFAULT)
  1230.     elog(NOTICE, "BeginTransactionBlock and not in default state ");
  1231.     
  1232.     /* ----------------
  1233.      *    set the current transaction block state information
  1234.      *  appropriately during begin processing
  1235.      * ----------------
  1236.      */
  1237.     s->blockState = TBLOCK_BEGIN;
  1238.     
  1239.     /* ----------------
  1240.      *    do begin processing
  1241.      * ----------------
  1242.      */
  1243.     
  1244.     /* ----------------
  1245.      *    done with begin processing, set block state to inprogress
  1246.      * ----------------
  1247.      */
  1248.     s->blockState = TBLOCK_INPROGRESS;    
  1249. }
  1250.  
  1251. /* --------------------------------
  1252.  *    EndTransactionBlock
  1253.  * --------------------------------
  1254.  */
  1255. void
  1256. EndTransactionBlock()
  1257. {
  1258.     TransactionState s = CurrentTransactionState;
  1259.     
  1260.     /* ----------------
  1261.      *    check the current transaction state
  1262.      * ----------------
  1263.      */
  1264.     if (s->state == TRANS_DISABLED)
  1265.     return;
  1266.     
  1267.     if (s->blockState == TBLOCK_INPROGRESS) {
  1268.     /* ----------------
  1269.      *  here we are in a transaction block which should commit
  1270.      *  when we get to the upcoming CommitTransactionCommand()
  1271.      *  so we set the state to "END".  CommitTransactionCommand()
  1272.      *  will recognize this and commit the transaction and return
  1273.      *  us to the default state
  1274.      * ----------------
  1275.      */
  1276.     s->blockState = TBLOCK_END;
  1277.     return;
  1278.     }
  1279.  
  1280.     if (s->blockState == TBLOCK_ABORT) {
  1281.     /* ----------------
  1282.      *  here, we are in a transaction block which aborted
  1283.      *  and since the AbortTransaction() was already done,
  1284.      *  we do whatever is needed and change to the special
  1285.      *  "END ABORT" state.  The upcoming CommitTransactionCommand()
  1286.      *  will recognise this and then put us back in the default
  1287.      *  state.
  1288.      * ----------------
  1289.      */
  1290.     s->blockState = TBLOCK_ENDABORT;
  1291.     return;
  1292.     }
  1293.     
  1294.     /* ----------------
  1295.      *    We should not get here, but if we do, we go to the ENDABORT
  1296.      *  state after printing a warning.  The upcoming call to
  1297.      *  CommitTransactionCommand() will then put us back into the
  1298.      *  default state.
  1299.      * ----------------
  1300.      */
  1301.     elog(NOTICE, "EndTransactionBlock and not inprogress/abort state ");
  1302.     s->blockState = TBLOCK_ENDABORT;
  1303. }
  1304.  
  1305. /* --------------------------------
  1306.  *    AbortTransactionBlock
  1307.  * --------------------------------
  1308.  */
  1309. void
  1310. AbortTransactionBlock()
  1311. {
  1312.     TransactionState s = CurrentTransactionState;
  1313.  
  1314.     /* ----------------
  1315.      *    check the current transaction state
  1316.      * ----------------
  1317.      */
  1318.     if (s->state == TRANS_DISABLED)
  1319.     return;
  1320.     
  1321.     if (s->blockState == TBLOCK_INPROGRESS) {
  1322.     /* ----------------
  1323.      *  here we were inside a transaction block something
  1324.      *  screwed up inside the system so we enter the abort state,
  1325.      *  do the abort processing and then return.
  1326.      *  We remain in the abort state until we see the upcoming
  1327.      *  END TRANSACTION command.
  1328.      * ----------------
  1329.      */
  1330.     s->blockState = TBLOCK_ABORT;
  1331.     
  1332.     /* ----------------
  1333.      *  do abort processing and return
  1334.      * ----------------
  1335.      */
  1336.     AbortTransaction();
  1337.     return;
  1338.     }
  1339.  
  1340.     /* ----------------
  1341.      *    this case should not be possible, because it would mean
  1342.      *  the user entered an "abort" from outside a transaction block.
  1343.      *  So we print an error message, abort the transaction and
  1344.      *  enter the "ENDABORT" state so we will end up in the default
  1345.      *  state after the upcoming CommitTransactionCommand().
  1346.      * ----------------
  1347.      */
  1348.     elog(NOTICE, "AbortTransactionBlock and not inprogress state");
  1349.     AbortTransaction();
  1350.     s->blockState = TBLOCK_ENDABORT;
  1351. }
  1352.  
  1353. /* --------------------------------
  1354.  *    UserAbortTransactionBlock
  1355.  * --------------------------------
  1356.  */
  1357. void
  1358. UserAbortTransactionBlock()
  1359. {
  1360.     TransactionState s = CurrentTransactionState;
  1361.  
  1362.     /* ----------------
  1363.      *    check the current transaction state
  1364.      * ----------------
  1365.      */
  1366.     if (s->state == TRANS_DISABLED)
  1367.     return;
  1368.     
  1369.     if (s->blockState == TBLOCK_INPROGRESS) {
  1370.     /* ----------------
  1371.      *  here we were inside a transaction block and we
  1372.      *  got an abort command from the user, so we move to
  1373.      *  the abort state, do the abort processing and
  1374.      *  then change to the ENDABORT state so we will end up
  1375.      *  in the default state after the upcoming
  1376.      *  CommitTransactionCommand().
  1377.      * ----------------
  1378.      */
  1379.     s->blockState = TBLOCK_ABORT;
  1380.     
  1381.     /* ----------------
  1382.      *  do abort processing
  1383.      * ----------------
  1384.      */
  1385.     AbortTransaction();
  1386.     
  1387.     /* ----------------
  1388.      *  change to the end abort state and return
  1389.      * ----------------
  1390.      */
  1391.     s->blockState = TBLOCK_ENDABORT;
  1392.     return;
  1393.     }
  1394.  
  1395.     /* ----------------
  1396.      *    this case should not be possible, because it would mean
  1397.      *  the user entered an "abort" from outside a transaction block.
  1398.      *  So we print an error message, abort the transaction and
  1399.      *  enter the "ENDABORT" state so we will end up in the default
  1400.      *  state after the upcoming CommitTransactionCommand().
  1401.      * ----------------
  1402.      */
  1403.     elog(NOTICE, "UserAbortTransactionBlock and not inprogress state");
  1404.     AbortTransaction();
  1405.     s->blockState = TBLOCK_ENDABORT;
  1406. }
  1407.  
  1408. bool
  1409. IsTransactionBlock()
  1410. {
  1411.     TransactionState s = CurrentTransactionState;
  1412.  
  1413.     if (s->blockState == TBLOCK_INPROGRESS
  1414.     || s->blockState == TBLOCK_ENDABORT) {
  1415.     return (true);
  1416.     }
  1417.  
  1418.     return (false);
  1419. }
  1420.